package eatwatch;

import java.util.*;
import java.io.*;

/**
 *	Holds the information related to field types
 */
public class DataDefinition
{
	private class Field
	{
		private Class  mType = null;
		private String mName = null;

		public Field (String name, Class type)
		{
			mType = type;
			mName = name;
		}

		public Class GetType ()
		{
			return mType;
		}

		public String GetName ()
		{
			return mName;
		}
	}

	private Vector mFields = null;

	public DataDefinition (Record record)
	{
		mFields = new Vector ();
		for (Enumeration e = record.GetNames (); e.hasMoreElements();) {
			String name  = (String) e.nextElement ();
			Object value = record.GetField (name);
			mFields.addElement (new Field (name, value.getClass ()));
		}
	}

	/**
	 *	Read the data definition from an array of bytes (first record in a table)
	 */
	public DataDefinition (byte[] data)
	{
		ByteArrayInputStream bais = new ByteArrayInputStream (data);
		DataInputStream      dis  = new DataInputStream (bais);

		mFields = new Vector ();
		while (bais.available () > 0) try {
			String str  = (String) dis.readUTF ();
			String name = str.substring (0, str.indexOf ('|'));
			String type = str.substring (str.indexOf ('|') + 1);
			mFields.addElement (new Field (name, Class.forName (type)));
		}
		catch (EOFException ignore) {}
		catch (IOException ex) {ex.printStackTrace (); }
		catch (ClassNotFoundException ex) {ex.printStackTrace (); }
	}

	/**
	 *	Writes the data definition to an array of bytes (first record in a table)
	 */
	public byte[] GetDataDefinitionBytes ()
	{
		ByteArrayOutputStream baos = new ByteArrayOutputStream ();
		DataOutputStream      dos  = new DataOutputStream (baos);
		try {
			for (int i = 0; i < mFields.size (); ++i) {
				Field field = (Field) mFields.elementAt (i);
				String name  = field.GetName ();
				String type  = field.GetType ().getName ();

				dos.writeUTF (name + "|" + type);
			}
		}
		catch (IOException ignore) {}
		return baos.toByteArray ();
	}

	public byte[] Write (Record record)
	{
		ByteArrayOutputStream baos = new ByteArrayOutputStream ();
		DataOutputStream      dos  = new DataOutputStream (baos);
		try {
			for (int i = 0; i < mFields.size (); ++i) {
				String name  = ((Field) mFields.elementAt (i)).GetName ();
				Object value = record.GetField (name);
				String type = value.getClass ().getName ();

				if (type.equals("java.lang.String"))
					dos.writeUTF ((String) value);
				else if (type.equals("java.lang.Float"))
					dos.writeFloat (((Float) value).floatValue ());
				else if (type.equals("java.util.Date"))
					dos.writeLong (((Date) value).getTime ());
				else if (type.equals("java.lang.Integer"))
					dos.writeInt (((Integer) value).intValue ());
				else
					throw new RuntimeException ("type not handled: " + type);
			}
		}
		catch (IOException ignore) {}
		return baos.toByteArray ();
	}

	public Record Read (byte[] data)
	{
		ByteArrayInputStream bais = new ByteArrayInputStream (data);
		DataInputStream      dis  = new DataInputStream (bais);

		Record record = new Record ();
		try {
			for (int i = 0; i < mFields.size (); ++i) {
				Field field = (Field) mFields.elementAt (i);
				String name  = field.GetName ();
				String type  = field.GetType ().getName ();
				Object value = null;

				if (type.equals("java.lang.String"))
					value = dis.readUTF ();
				else if (type.equals("java.util.Date"))
					value = new Date (dis.readLong ());
				else if (type.equals("java.lang.Float"))
					value = new Float (dis.readFloat ());
				else if (type.equals("java.lang.Integer"))
					value = new Integer (dis.readInt ());
				else
					throw new RuntimeException ("type not handled: " + type);
				record.SetField (name, value);
			}
		}
		catch (IOException ignore) {}
		return record;
	}
}